/*
 * Copyright (c) 2010, Google, Inc.
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/*
 * @file
 * WebP demuxer
 * http://code.google.com/p/webp
 *
 * supports metadata: artist, copyright, title, comment
 * Encoding/decoding examples:
 *  ffmpeg -i my_image
 *     -metadata artist=me -metadata title="sunset"
 *     -metadata copyright=2010 -metadata comment="nice pic!"
 *     -profile 1 -qmin 5 my_image.webp
 *  ffmpeg -i my_image.webp -y my_image.png
 */

#include "webp.h"
#include "libavutil/intreadwrite.h"

static const AVCodecTag webp_codec_tags[] = {
    { CODEC_ID_VP8,    MKTAG('V', 'P', '8', ' ') },
    { CODEC_ID_NONE,   0 }
};

static int probe(AVProbeData *p)
{
    if (!memcmp(p->buf, "RIFF", 4) && !memcmp(p->buf + 8, "WEBP", 4))
        return AVPROBE_SCORE_MAX;

    return 0;
}

static int read_header(AVFormatContext *s, AVFormatParameters *ap)
{
    AVStream *st;
    uint32_t riff_size;

    if (get_le32(s->pb) != AV_RL32("RIFF"))
        return AVERROR(EINVAL);
    riff_size = get_le32(s->pb);
    if (get_le32(s->pb) != AV_RL32("WEBP"))
        return AVERROR(EINVAL);

    st = av_new_stream(s, 0);
    if (!st)
        return AVERROR(ENOMEM);

    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
    st->codec->codec_tag  = AV_RL32("VP8 ");
    st->codec->codec_id   = ff_codec_get_id(webp_codec_tags,
                                            st->codec->codec_tag);
    av_set_pts_info(st, 24, 1, 1000);

    return 0;
}

static int set_metadata(ByteIOContext* pb, AVMetadata** metadata,
                        const char* generic_key, uint32_t size)
{
    char* const value = av_malloc(size + 1);
    if (!value)
        return AVERROR(ENOMEM);
    if (get_buffer(pb, value, size) < 0)
        return AVERROR(EINVAL);
    value[size] = 0;
    if (av_metadata_set2(metadata, generic_key, value, 0))
        return AVERROR(EINVAL);
    av_free(value);
    return size;
}

static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
    int ret = -1;
    AVStream *stream = s->streams[pkt->stream_index];
    uint32_t tag = get_le32(s->pb);
    uint32_t chunk_size = get_le32(s->pb);
    if (tag == stream->codec->codec_tag) {
        ret = av_get_packet(s->pb, pkt, chunk_size);
        pkt->flags |= AV_PKT_FLAG_KEY;
    }
    else {
        int i;
        for (i = 0; ff_webp_metadata_conv[i].native; ++i) {
            const char* native_tag = ff_webp_metadata_conv[i].native;
            if (tag == AV_RL32(native_tag)) {
                ret = set_metadata(s->pb, &stream->metadata,
                                   ff_webp_metadata_conv[i].generic,
                                   chunk_size);
                break;
            }
        }
    }
    return ret;
}

static int read_close(struct AVFormatContext *s)
{
    return 0;
}

AVInputFormat webp_demuxer = {
    .name           = "webp",
    .long_name      = NULL_IF_CONFIG_SMALL("WebP"),
    .priv_data_size = 0,
    .read_probe     = probe,
    .read_header    = read_header,
    .read_packet    = read_packet,
    .read_close     = read_close,
    .flags          = AVFMT_GENERIC_INDEX,
    .extensions     = "webp",
    .value          = CODEC_ID_VP8,
    .codec_tag      = (const AVCodecTag*[]){webp_codec_tags, 0},
};
